/*
 * SiFiSy - A File System Simulator
 * Copyright (C) 2010  SevenSoft
 *
 * This file is part of SiFiSy.
 *
 * SiFiSy is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * SiFiSy is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with SiFiSy.  If not, see <http://www.gnu.org/licenses/>.
 */

package sifisy.core;

import java.util.Vector;
import org.jdom.*;
import java.util.List;
import sifisy.newgui.SimulationPanel;

/**
 * Project is the class used to represent a SiFiSy project.
 * Project provide all the functions of a project.
 * @author Alessandro Vedovato
 * @version %I%, %G%
 * @createData 20/02/2010
 */
public class Project {
    private String name;
    private Vector<Integer> simulationsRef;
    private Vector<Integer> compare;
    private boolean modified;
    private Vector<Integer> bestCompare;


    /**
     * Constructor of a project with stardard name
     * simulationsRef is empty.
     */
    public Project() {
        this("New Project");
    }

    public int numberOfSimulation(){
        return simulationsRef.size();
    }

    /**
     * Constructor of a project with given name
     * @param name: name of the new project
     */
    public Project(String name) {
        this.name = name;
        simulationsRef = new Vector<Integer>();
        compare = new Vector<Integer>();
        bestCompare = new Vector<Integer>();
        modified = true;
    }

    /**
     * Save the project
     * @param projectRoot
     */
    public void save(Element projectRoot) {
        //if (modified == true) {
            projectRoot.addContent(new Element("name").addContent(name));
            for (int i = 0; i < simulationsRef.size(); i++ ) {
                Element simulationRoot = new Element("simulation");
                simulationRoot.
                        setAttribute(new Attribute("id", String.valueOf(i)));
                Model.getSimulations().elementAt((simulationsRef.elementAt(i)))
                        .save(simulationRoot);
                projectRoot.addContent(simulationRoot);
            }
        //}
    }

    /**
     * Opens a previously saved project
     * @param projectRoot
     */
    public void open(Element projectRoot) {
        name = projectRoot.getChild("name").getText();
        List sims = projectRoot.getChildren("simulation");
        for (int i = 0; i < sims.size(); i++) {
            Simulation newSimulation = null;

            System.err.println(((Element)sims.get(i)).getText());
            Element newSimulationRoot = (Element)(sims.get(i));
            Element fileSystemRoot = (org.jdom.Element)
                    (newSimulationRoot.getChild("fileSystem"));
            String type = fileSystemRoot.getChild("type").getText();
            if (type.equals("Ext2")) {
                newSimulation = new Ext2();
            }
            if (type.equals("Fat32")) {
                newSimulation = new Fat32();
            }
            if (type.equals("NTFS")) {
                newSimulation = new Ntfs();
            }
            if (newSimulation == null) {
                System.err.println("Simulazione " + String.valueOf(i) + " non trovata.");
                return;
            }
            newSimulation.open(newSimulationRoot);
            Model.getSimulations().add(newSimulation);
            //this.addSimulation(Model.getSimulations().size() - 1);
        }
        modified = false;
    }

    /**
     * Aggiunge una simulazione al vector e ne ritorna l'indice
     * @param Simulazione da aggiungere
     * @return Indice della simulazione all'interno del progetto
     */
    public int addSimulation(Integer simulationId){
        simulationsRef.add(simulationId);
        return (simulationsRef.size()-1);
    }

    /**
     * Importa una simulazione esistente nel progetto e ne ritorna l'indice
     * @param Simulazione da aggiungere
     * @return Indice della simulazione
     */
    private int importSimulation(String filePath){
        int simulationId = -1;
        simulationId = Model.openSimulation(filePath);
        if (simulationId != -1)
            simulationsRef.add(simulationId);
        else
            System.err.println("Error while opening simulation: ' " + filePath + "'");
        return (simulationId);
    }

    /**
     * Importa una simulazione esistente nel progetto e ne ritorna l'indice
     * @param Simulazione da aggiungere
     * @return Indice della simulazione
     */
    public void importSimulation(String filePath, SimulationPanel panel) {
        int simulationId = -1;

        simulationId = importSimulation(filePath);
        panel.notifyPanel(simulationId);
    }

    /**
     * Rimuove una simulazione dal vector impostando il riferimento del
     * vettore a null
     * @param Indice della simulazione da rimuovere
     */
    public void removeSimulation(int simId){
        //simulationsRef.setElementAt(null, simId);
        compare.remove(new Integer(simId));
        simulationsRef.remove(new Integer(simId));
    }
    
    /**
     * Ritorna la simulazione identificata dall'indice simId
     * @param Indice della simulazione interessata
     * @return La simulazione
     */
    public Integer getSimulation(int simId) {
        return simulationsRef.elementAt(simId);
    }

    /**
     * Add a simulation already existing in the project to compare the list
     * @param simId: the id of the simulation
     */
    public void addCompare(Integer simId){
        compare.add(simId);
    }

    /**
     * Remove a simulation already existing in the project from compare the list
     * @param simId: the id of the simulation
     */
    public void removeCompare(Integer simId){
        compare.remove(simId);
    }

    /**
     * Call start() for every simulation found in the compare list
     */
    public void compare(){
        for (int i = 0; i < compare.size(); i++) {
            Model.getSimulations().elementAt(compare.elementAt(i)).start();
        }
        // altrimenti la dimensione del vector e' a 0 e non posso usare
        // bestCompare.set(idx, value);
        bestCompare.clear();
        bestCompare.add(new Integer(0));
        bestCompare.add(new Integer(0));
        bestCompare.add(new Integer(0));
        bestCompare.add(new Integer(0));
    }
    
    /**
     * Do a compare of the overhead of the selected simulations
     */
    public void compareOverhead(){
        int best = -1;
        double bestOverhead = 100;
        double tempOverhead = 0;
        for (int i = 0; i < compare.size(); i++) {
             tempOverhead = Model.getSimulations().
                    elementAt(compare.elementAt(i)).getInflationIndex();
            if(tempOverhead < bestOverhead){
                best = compare.elementAt(i);
                bestOverhead = tempOverhead;
            }
        }
        bestCompare.set(0, best);
    }

    /**
     * Compare more simulations on the parameter External Fragmentation and returns the name of the simulation with the length greater
     * @return String
     */
//    public String compareExternalFragmentaion() {
//        int controlNumber = sim.size();
//        Simulation currentSimulation;
//        String simulationName = "";
//        int maxExternalFragmentation = 0;
//        for (int index = 0; index < controlNumber; index++) {
//            currentSimulation = sim.get(index);
//            //refresh(currentSimulation);
//            int fragmentation = currentSimulation.getExternalFragmentation();
//            if (maxExternalFragmentation < fragmentation) {
//                maxExternalFragmentation = fragmentation;
//                simulationName = currentSimulation.getName();
//            }
//        }
//        return simulationName;
//    }

    /**
     * Compare more simulations on the parameter maximum length of a file and
     * return the name of the simulation with the length greater
     * @return String
     */
    public void compareMaxLenghtFile(){
        long maxLength = 0;
        int bestIndex = -1;
        long tempLength = 0;
        for (int i = 0; i < compare.size(); i++) {
             tempLength = Model.getSimulations().
                    elementAt(compare.elementAt(i)).getMaxLenghtFile();
            if(tempLength > maxLength){
                bestIndex = compare.elementAt(i);
                maxLength = tempLength;
            }
        }
        bestCompare.set(1, bestIndex);
    }

    /**
     * Do a compare of the file system size of the selected simulations
     */
    public void compareFileSystem(){
        double maxFS = 0;
        int bestIndex = -1;
        double tempFS = 0;
        for (int i = 0; i < compare.size(); i++) {
             tempFS = Model.getSimulations().
                    elementAt(compare.elementAt(i)).getSizeFileSystem();
            if(tempFS > maxFS){
                bestIndex = compare.elementAt(i);
                maxFS = tempFS;
            }
        }
        bestCompare.set(2, bestIndex);
    }

     /**
     * Compare more simulations on the parameter Internal Fragmentation and returns the name of the simulation with the length greater
     * @return String
     */
    public void compareInternalFragmentation() {
        double minFrag = 0;
        int bestIndex = -1;
        double tempFrag = 0;
        for (int i = 0; i < compare.size(); i++) {
            tempFrag = Model.getSimulations().
                    elementAt(compare.elementAt(i)).getInternalFragmentation();
            if (tempFrag < minFrag) {
                bestIndex = compare.elementAt(i);
                minFrag = tempFrag;
            }
        }
        bestCompare.set(3, bestIndex);
    }

    /**
     * Sets the name of a project
     * @param parName
     */
    public void setName(String parName){
        name=parName;
    }

    /**
     * Returns the name of a project
     * @return
     */
    public String getName(){
        return name;
    }

    /**
     * Sets if the project was modified after opening or creating
     * @param parModified
     */
    public void setModified(boolean parModified){
        modified=parModified;
    }

    /**
     * Returns if the project was modified after opening or creating
     * @return boolean
     */
    public boolean getModified(){
        return modified;
    }

    /**
     * Return the bestCompare vector
     * @return the bestCompare vector
     */
    public Vector<Integer> getBestCompare() {
        return bestCompare;
    }

    /**
     * Return the compare vector
     * @return the compare vector
     */
    public Vector<Integer> getCompare() {
        return compare;
    }

    /**
     * Return the vector containing the references of the simulations in the project
     * @return the vector of simulations in the project
     */
    public Vector<Integer> getSimulationsRef() {
        return simulationsRef;
    }
}
